package console

import (
	"fmt"
)

type token struct {
	t     tokenType
	value string
}

func (t token) String() string {
	return fmt.Sprintf("[%v : %s]", t.t, t.value)
}

type scanner struct {
	input <-chan []rune
	chunk []rune
	start int
	width int
	read  int
	err   error
	out   chan *token
}

func newScanner() *scanner {
	return &scanner{
		input: make(chan []rune, 4),
		start: 0,
		width: 0,
		out:   make(chan *token, 1),
	}
}

func (s *scanner) Input() interface{} {
	return &s.input
}

func (s *scanner) Output() interface{} {
	return s.out
}

func (s *scanner) emit(t tokenType) {
	tok := string(s.chunk[s.start : s.start+s.width])
	s.out <- &token{t, tok}
	s.ignore()
}

func (s *scanner) accept() {
	if s.start+s.width < len(s.chunk) {
		s.width += 1
	}
}

func (s *scanner) ignore() {
	s.start += s.width
	s.read += s.width
	s.width = 0
}

func (s *scanner) backup() {
	if s.width > 0 {
		s.width -= 1
	}
}

func (s *scanner) pop() (r rune) {
	if s.start+s.width < len(s.chunk) {
		r = s.chunk[s.start+s.width]
		s.width += 1
	} else {
		r = eof
	}
	return
}

func (s *scanner) init() {
	s.start = 0
	s.width = 0
	s.err = nil
}

func (s *scanner) run() {
	fmt.Printf("Starting scanner %v\n", s)
	for {
		select {
		case s.chunk = <-s.input:
			fmt.Printf("parsing %q\n", string(s.chunk))
			s.init()
			s.scan()
		}
	}
}

func (s *scanner) scan() {
	for status := readToken; status != nil; status = status(s) {
	}
}
